package cn.qfei.qiyuesuo.service.feishu.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import cn.qfei.qiyuesuo.common.Constant;
import cn.qfei.qiyuesuo.bo.ClientModel;
import cn.qfei.qiyuesuo.interceptor.FeishuApiRetryInterceptor;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.lark.oapi.Client;
import com.lark.oapi.core.enums.BaseUrlEnum;
import com.lark.oapi.core.exception.ObtainAccessTokenException;
import com.lark.oapi.core.httpclient.OkHttpTransport;
import com.lark.oapi.core.request.RequestOptions;
import com.lark.oapi.core.utils.Jsons;
import com.lark.oapi.core.utils.Lists;
import com.lark.oapi.okhttp.OkHttpClient;
import com.lark.oapi.service.auth.v3.model.*;
import com.lark.oapi.service.contact.v3.enums.DepartmentIdTypeEnum;
import com.lark.oapi.service.contact.v3.enums.UserIdTypeEnum;
import com.lark.oapi.service.contact.v3.model.*;
import com.lark.oapi.service.tenant.v2.model.QueryTenantResp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 飞书客户端工具类
 *
 * @author guanfeng
 * @date 2023/2/21 11:22
 */
@Slf4j
public class FeishuClientUtils {

    public static final Client getClient(String appId, String appSecret) {
        Client client = Client.newBuilder(appId, appSecret)
                // 设置域名，默认为飞书
                .openBaseUrl(BaseUrlEnum.FeiShu)
                // 设置httpclient 超时时间，默认永不超时
                .requestTimeout(5, TimeUnit.SECONDS)
                // 在 debug 模式下会打印 http 请求和响应的 headers,body 等信息。
                .logReqAtDebug(true)
                .httpTransport(new OkHttpTransport(
                        new OkHttpClient().newBuilder()
                                .callTimeout(10, TimeUnit.SECONDS)
                                .connectTimeout(3, TimeUnit.SECONDS)
                                .readTimeout(5, TimeUnit.SECONDS)
                                .writeTimeout(5, TimeUnit.SECONDS)
                                .addInterceptor(new FeishuApiRetryInterceptor(3))
                                .build()))
                .build();
        return client;
    }

    public static  String getAppAccessTokenReqBody(String appId, String appSecret,String ticket) throws Exception {
        // 构建client
        Client client = Client.newBuilder(appId,appSecret).build();

        // 创建请求对象
        CreateAppAccessTokenReq req = CreateAppAccessTokenReq.newBuilder()
                .createAppAccessTokenReqBody(CreateAppAccessTokenReqBody.newBuilder()
                        .appId(appId)
                        .appSecret(appSecret)
                        .appTicket(ticket)
                        .build())
                .build();

        // 发起请求
        CreateAppAccessTokenResp resp = client.auth().v3().appAccessToken().create(req);

        // 处理服务端错误
        if (!resp.success()) {
            System.out.println(java.lang.String.format("code:%s,msg:%s,reqId:%s", resp.getCode(), resp.getMsg(), resp.getRequestId()));
            throw new Exception("获取商店token失败！");

        }
//{"app_access_token":"a-g10439cWVHLZ2AFHANB7A2YCMNVTYMSP5OMWECWR","code":0,"expire":7104,"msg":"ok"}
        String str = new String(resp.getRawResponse().getBody());
        Map<String,Object> map = JSONUtil.toBean(str, Map.class);
        return map.get("app_access_token").toString();
    }
    public static  String getTenantTokenReqBody(String appId, String appSecret,String tenantKey,String ticket) throws Exception {
        // 构建client
        Client client = Client.newBuilder(appId, appSecret).build();

        String appAccessToken = getAppAccessTokenReqBody(appId,appSecret,ticket);
        //System.out.println("apptoken"+appAccessToken);

        // 创建请求对象
        CreateTenantAccessTokenReq req = CreateTenantAccessTokenReq.newBuilder()
                .createTenantAccessTokenReqBody(CreateTenantAccessTokenReqBody.newBuilder()
                        .appAccessToken(appAccessToken)
                        .tenantKey(tenantKey)
                        .build())
                .build();

        // 发起请求
        CreateTenantAccessTokenResp resp = client.auth().v3().tenantAccessToken().create(req);

        // 处理服务端错误
        if (!resp.success()) {
            System.out.println(java.lang.String.format("code:%s,msg:%s,reqId:%s"
                    , resp.getCode(), resp.getMsg(), resp.getRequestId()));
            throw  new Exception("获取租户token失败！");
        }

        String str = new String(resp.getRawResponse().getBody());
        Map<String,Object> map = JSONUtil.toBean(str, Map.class);
        return map.get("tenant_access_token").toString();
    }


    public static User getUserInfo(Client client, String openId, String tenantTokenReqBody) throws Exception {

        // 创建请求对象
        GetUserReq req = GetUserReq.newBuilder()
                .userId(openId)
                .userIdType("open_id")
                .build();

        // 发起请求
        GetUserResp resp = client.contact().v3().user().get(req,RequestOptions.newBuilder()
                .userAccessToken(tenantTokenReqBody)
                .build());



        // 处理服务端错误
        if (!resp.success()) {
            System.out.println(java.lang.String.format("code:%s,msg:%s,reqId:%s"
                    , resp.getCode(), resp.getMsg(), resp.getRequestId()));
            throw  new Exception("获取用户信息失败！");
        }

        return resp.getData().getUser();
    }


    //获取父级节点的部门
    public static String getParentDepartmentInfo(Client client, String departmentId, String tenantTokenReqBody) throws Exception {
        // 创建请求对象
        ParentDepartmentReq req = ParentDepartmentReq.newBuilder()
                .departmentId(departmentId)
                .build();

        // 发起请求
        ParentDepartmentResp resp = client.contact().department().parent(req, RequestOptions.newBuilder().userAccessToken(tenantTokenReqBody).build());

        // 处理服务端错误
        if(!resp.success()) {
            System.out.println(String.format("code:%s,msg:%s,reqId:%s", resp.getCode(), resp.getMsg(), resp.getRequestId()));
            return null;
        }

        String str = new String(resp.getRawResponse().getBody());
        Map<String,Object> map = JSONUtil.toBean(str, Map.class);
        String data = map.get("data").toString();
        JSONObject bean = JSONUtil.toBean(data, JSONObject.class);
        String arrayStr = bean.getString("items");
        JSONArray objects = JSONArray.parseArray(arrayStr);

        for (int i = 0; i < objects.size(); i++) {
            JSONObject obj = (JSONObject) objects.get(i);
            if(!StringUtils.isEmpty(obj.getString("parent_department_id")) && obj.getString("parent_department_id").equals("0") ){
                return obj.getString("department_id");
            }
        }

        return null;

    }


    //获取节点下的所有子部门信息

    public static String getDepartmentChildrenInfo(Client client, String departmentId, String tenantToken) throws Exception {

        // 创建请求对象
        ChildrenDepartmentReq req = ChildrenDepartmentReq.newBuilder()
                .departmentId(departmentId)
                .build();

        // 发起请求
        ChildrenDepartmentResp resp = client.contact().department().children(req, StringUtils.isEmpty(tenantToken)?  RequestOptions.newBuilder()
                .build():RequestOptions.newBuilder()
                .userAccessToken(tenantToken)
                .build());

        // 处理服务端错误
        if(!resp.success()) {
            System.out.println(String.format("code:%s,msg:%s,reqId:%s", resp.getCode(), resp.getMsg(), resp.getRequestId()));
            return null;
        }

        String str = new String(resp.getRawResponse().getBody());
        Map<String,Object> map = JSONUtil.toBean(str, Map.class);
        return map.get("data").toString();
    }

    private static boolean getUserListBy(String departmentId, String pageToken, Client feishuClient, List<User> userList, String tenantTokenReqBody) {
        // 创建请求对象
        ListUserReq req = ListUserReq.newBuilder().userIdType(UserIdTypeEnum.UNION_ID.getValue()).departmentIdType(DepartmentIdTypeEnum.OPEN_DEPARTMENT_ID.getValue()).departmentId(departmentId).pageToken(pageToken).pageSize(50).build();
        try {
            ListUserResp listUserResp = feishuClient.contact().user().list(req ,RequestOptions.newBuilder()
                    .userAccessToken(tenantTokenReqBody)
                    .build());
            if (!listUserResp.success()) {
                return false;
            }
            ListUserRespBody listUserRespBody = listUserResp.getData();
            if (!org.springframework.util.ObjectUtils.isEmpty(listUserRespBody.getItems())) {
                Collections.addAll(userList, listUserRespBody.getItems());
            }
            if (!ObjectUtils.isEmpty(listUserRespBody.getPageToken()) && listUserRespBody.getHasMore()) {
                return getUserListBy(departmentId, listUserRespBody.getPageToken(), feishuClient, userList,tenantTokenReqBody);
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    public static String getAppName(String appId, String appSecret, String appKey, String token) throws Exception {
        // 封装header
        Map<String, List<String>> headers = new HashMap<>();
        if (!StringUtils.isEmpty(token)) {
            headers.put("Authorization", Lists.newArrayList("Bearer " + token));
        }
        QueryTenantResp resp;
        //发送请求
        if(!StringUtils.isEmpty(token)){
            Client client = getIsvClient(appId, appSecret);
            resp=  client.tenant().tenant().query(RequestOptions.newBuilder().tenantAccessToken(token).build());
        }else {
            resp=  getClient(appId,appSecret).tenant().tenant().query();
        }

        // 处理服务端错误
        if (!resp.success()) {
            System.out.println(String.format("code:%s,msg:%s,reqId:%s", resp.getCode(), resp.getMsg(), resp.getRequestId()));
            return null;
        }

        String str = new String(resp.getRawResponse().getBody());
        JSONObject bodyObj = JSONUtil.toBean(str, JSONObject.class);

        if ("0".equals(bodyObj.getString("code"))) {
            JSONObject dataObj = JSONUtil.toBean(bodyObj.getString("data"), JSONObject.class);
            JSONObject tenant = JSONUtil.toBean(dataObj.getString("tenant"), JSONObject.class);
            String name = tenant.getString("name");
            if(StringUtils.isNotEmpty(name)){
                //
                int index = StrUtil.indexOf(name, '|');
                if(index!=-1){
                    name= StrUtil.sub(name, 0, index);
                }
            }
            return name;
        }
        return null;
//
//        HttpRequest httpRequest = HttpRequest.get("https://open.feishu.cn/open-apis/tenant/v2/tenant/query").header("Authorization",
//                "Bearer " + token);
//        String body = httpRequest.execute().body();
//        System.out.println(body);
//
//        JSONObject bodyObj = JSONUtil.toBean(body, JSONObject.class);
//
//        if ("0".equals(bodyObj.getString("code"))) {
//            JSONObject dataObj = JSONUtil.toBean(bodyObj.getString("data"), JSONObject.class);
//            JSONObject tenant = JSONUtil.toBean(dataObj.getString("tenant"), JSONObject.class);
//            return tenant.getString("name");
//        }
//        return null;
    }




    public  static String getApplicationUser(String token){
        HttpRequest httpRequest = HttpRequest.get("https://open.feishu.cn/open-apis/user/v4/app_admin_user/list").header("Authorization",
                "Bearer " + token).header("Content-Type","application/json; charset=utf-8");
        String body = httpRequest.execute().body();
        System.out.println(body);

        JSONObject bodyObj = JSONUtil.toBean(body, JSONObject.class);

        if ("0".equals(bodyObj.getString("code"))) {
            JSONObject dataObj = JSONUtil.toBean(bodyObj.getString("data"), JSONObject.class);

            JSONArray userList = dataObj.getJSONArray("user_list");
            List<String> openIds = new ArrayList<>();
            if(userList!=null){
                for (int i = 0; i < userList.size(); i++) {
                    JSONObject e = userList.getJSONObject(i);
                    openIds.add(e.getString("open_id"));
                }
            }
            return JSONUtil.toJsonStr(openIds);
        }

        return null;
    }


    public static String getInternalToken(String appId, String appSecret) throws Exception{
        // 构建client
        Client client = Client.newBuilder(appId,appSecret).build();

        // 创建请求对象
        InternalTenantAccessTokenReq req = InternalTenantAccessTokenReq.newBuilder()
                .internalTenantAccessTokenReqBody(InternalTenantAccessTokenReqBody.newBuilder()
                        .appId(appId)
                        .appSecret(appSecret)
                        .build())
                .build();

        // 发起请求
        InternalTenantAccessTokenResp resp = client.auth().tenantAccessToken().internal(req);

        // 处理服务端错误
        if(!resp.success()) {
            log.error(String.format("code:%s,msg:%s,reqId:%s", resp.getCode(), resp.getMsg(), resp.getRequestId()));
        }
        String body = new String(resp.getRawResponse().getBody());
        JSONObject bodyObj = JSONUtil.toBean(body, JSONObject.class);
        return bodyObj.getString("tenant_access_token");
    }


    public static void main(String[] args) throws Exception {
        String openId="ou_ff5a3743d6186f2642a9c86dfa05d9b1";
        Client client = Client.newBuilder("cli_a560d788f127d00c", "3NCVqw9Tkypvz497lPSbOgVP1xSxznLR").build();
        //  String tenantTokenReqBody = getTenantTokenReqBody("cli_a560d788f127d00c", "3NCVqw9Tkypvz497lPSbOgVP1xSxznLR", "1699769e77401758", "g1043taGFC32UMTDN6PU5ZFTG3MAAHILPV4WNLPK");
        //  System.out.println(tenantTokenReqBody);
        //String appInfo = getAppName("cli_a560d788f127d00c","3NCVqw9Tkypvz497lPSbOgVP1xSxznLR","169ccc39f3965758",tenantTokenReqBody);
        //System.out.println(appInfo);

//        String users = getApplicationUser(tenantTokenReqBody);
//        System.out.println(users);


        String token =getInternalToken("cli_a53ac893547f100c","e5JTOkk7QASn9oFk81CcBeFWffd5UKok");
        String applicationUser = getApplicationUser(token);
        System.out.println(applicationUser);


//
//        List<String> userIds=new ArrayList<>();
//        List<String> departmentIds = new ArrayList<>();
//         getParentDepartmentInfo("cli_a560d788f127d00c", "3NCVqw9Tkypvz497lPSbOgVP1xSxznLR", tenantTokenReqBody,userIds,departmentIds,null);
//        System.out.println(userIds);
//        System.out.println(departmentIds);

//        //获取当前人员的部门节点u
//        for (String userId : userIds) {
//            String currentDeptId = getUserInfo(client, userId,tenantTokenReqBody);
//            System.out.println(currentDeptId);
//        }
//        Client isvClient = getIsvClient("cli_a560d788f127d00c", "3NCVqw9Tkypvz497lPSbOgVP1xSxznLR");
//
//        List<Department> departments=new ArrayList<>();
//        List<User> userList=new ArrayList<>();
//
//        for (String departmentId : departmentIds) {
//            //String parentDepartment = getParentDepartmentInfo(client, departmentId, tenantTokenReqBody);
//            // 获取指定部门下的人员
//            // 构建client
//            getDepartmentByDeptId(isvClient,tenantTokenReqBody, departmentId,departments,userList);
//        }
//        System.out.println(userList);
//        System.out.println(departments);
//
//        List<String> collect = userList.stream().map(User::getOpenId).collect(Collectors.toList());
//        //与ids 取差集
//        boolean b = userIds.removeAll(collect);
//
//        //根据openId获取人员信息
//
//        for (String userId : userIds) {
//            userList.add(getUserInfo(isvClient, userId,tenantTokenReqBody));
//        }
//
//        List<Department> rootDeptList = departments.stream().filter(e -> e.getDepartmentId().equals("0")).collect(Collectors.toList());
//        if(CollectionUtils.isEmpty(rootDeptList)){
//            Department department = new Department();
//            department.setName(getAppName("cli_a560d788f127d00c","3NCVqw9Tkypvz497lPSbOgVP1xSxznLR","169ccc39f3965758",tenantTokenReqBody));
//            department.setDepartmentId("0");
//            department.setOpenDepartmentId("0");
//            rootDeptList.add(department);
//        }



//
//        ListDepartmentReq req = ListDepartmentReq.newBuilder().userIdType(UserIdTypeEnum.UNION_ID.getValue()).departmentIdType(DepartmentIdTypeEnum.OPEN_DEPARTMENT_ID.getValue()).parentDepartmentId("0").fetchChild(true).pageToken(null).pageSize(50).build();
//        ListDepartmentResp listDepartmentResp = client.contact().department().list(req, RequestOptions.newBuilder()
//                .userAccessToken(tenantTokenReqBody)
//                .build());
//        // 处理服务端错误
//        if (!listDepartmentResp.success()) {
//            System.out.println(java.lang.String.format("code:%s,msg:%s,reqId:%s"
//                    , listDepartmentResp.getCode(), listDepartmentResp.getMsg(), listDepartmentResp.getRequestId()));
//            throw  new Exception("获取租户token失败！");
//        }
//        String str = new String(listDepartmentResp.getRawResponse().getBody());
//        System.out.println(str);
//        Map<String,Object> map = JSONUtil.toBean(str, Map.class);
//        System.out.println(map.get("data"));
//
//        ArrayList<User> objects = new ArrayList<>();
//        //获取部门下的人员
//        getUserListBy("od-9a21941f597476c644988a952c6a520c",null, client,objects,tenantTokenReqBody );
//        objects.forEach(e->{
//            System.out.println(JSONUtil.toJsonStr(e));
//        });



    }

    public static void getFindByDepartmentUser(Client client, String tenantTokenReqBody, String deptId, List<Department> departments, List<User> userList) throws Exception {
        FindByDepartmentUserReq req = FindByDepartmentUserReq.newBuilder()
                .userIdType("open_id")
                .departmentIdType("open_department_id")
                .departmentId(deptId)
                .pageSize(10)
                .pageToken("")
                .build();

        // 发起请求
        FindByDepartmentUserResp resp = client.contact().v3().user().findByDepartment(req,  RequestOptions.newBuilder().tenantAccessToken(tenantTokenReqBody).build());
        // 创建请求对象

        // 处理服务端错误
        if(!resp.success()) {
            System.out.println(String.format("code:%s,msg:%s,reqId:%s", resp.getCode(), resp.getMsg(), resp.getRequestId()));
        }

        User[] items = resp.getData().getItems();
        if (null != items) {
            Collections.addAll(userList, items);
        }
    }





    public static Client getIsvClient(String appId, String appSecret) {
        return Client.newBuilder(appId, appSecret)
                .marketplaceApp() // 设置 app 类型为商店应用
                .openBaseUrl(BaseUrlEnum.FeiShu) // 设置域名，默认为飞书
                .helpDeskCredential("helpDeskId", "helpDeskSecret") // 服务台应用才需要设置
                .requestTimeout(3, TimeUnit.SECONDS) // 设置httpclient 超时时间，默认永不超时
                .disableTokenCache() // 禁用token管理，禁用后需要开发者自己传递token
                .logReqAtDebug(true) // 在 debug 模式下会打印 http 请求和响应的 headers,body 等信息。
                .build();
    }

    public static Department getDepartmentByDeptIdIsv(String appId,String appSecret, String tenantToken, String deptId) throws Exception {
        Client client;
        if (StringUtils.isNotEmpty(tenantToken)) {
            client = getIsvClient(appId, appSecret);
        } else {
            client = getClient(appId, appSecret);
        }
        // 创建请求对象
        GetDepartmentReq req = GetDepartmentReq.newBuilder()
                .departmentId(deptId)
                .userIdType("open_id")
                .departmentIdType("open_department_id")
                .build();

        // 发起请求
        GetDepartmentResp resp = client.contact().v3().department().get(req, StringUtils.isEmpty(tenantToken) ? RequestOptions.newBuilder().build() : RequestOptions.newBuilder().tenantAccessToken(tenantToken).build());

        // 处理服务端错误
        if(!resp.success()) {
            System.out.println(String.format("code:%s,msg:%s,reqId:%s", resp.getCode(), resp.getMsg(), resp.getRequestId()));
        }

        return resp.getData().getDepartment();
        //   getFindByDepartmentUser(client,tenantToken,deptId,departments,userList);
    }




    public static void getDepartmentByDeptId(Client client, String tenantToken, String deptId, List<Department> departments, List<User> userList) throws Exception {
        getChildrenDepartment(client,tenantToken,deptId,departments,userList);

        // 创建请求对象
        GetDepartmentReq req = GetDepartmentReq.newBuilder()
                .departmentId(deptId)
                .userIdType("open_id")
                .departmentIdType("open_department_id")
                .build();

        // 发起请求
        GetDepartmentResp resp = client.contact().v3().department().get(req, RequestOptions.newBuilder().tenantAccessToken(tenantToken).build());

        // 处理服务端错误
        if(!resp.success()) {
            System.out.println(String.format("code:%s,msg:%s,reqId:%s", resp.getCode(), resp.getMsg(), resp.getRequestId()));
        }

        Department department = resp.getData().getDepartment();

        departments.add(department);

        getFindByDepartmentUser(client,tenantToken,deptId,departments,userList);
    }



    public static void getChildrenDepartment(Client client, String tenantToken, String deptId, List<Department> departments, List<User> userList) throws Exception {

        // 创建请求对象
        ChildrenDepartmentReq req = ChildrenDepartmentReq.newBuilder()
                .departmentId(deptId)
                .userIdType("open_id")
                .departmentIdType("open_department_id")
                .fetchChild(false)
                .pageSize(50)
                .pageToken(null)
                .build();

        // 发起请求
        ChildrenDepartmentResp resp = client.contact().v3().department().children(req,RequestOptions.newBuilder().tenantAccessToken(tenantToken).build());

        // 处理服务端错误
        if(!resp.success()) {
            System.out.println(String.format("code:%s,msg:%s,reqId:%s", resp.getCode(), resp.getMsg(), resp.getRequestId()));
            return;
        }
        Department[] items = resp.getData().getItems();
        if(null!=items) {
            for (Department item : items) {
                getUserListBy(item.getOpenDepartmentId(),null,client,userList,tenantToken);
                getChildrenDepartment(client, tenantToken, item.getOpenDepartmentId(), departments, userList);
                //getFindByDepartmentUser(client, tenantToken, item.getOpenDepartmentId(), departments, userList);
                departments.add(item);
            }
        }

        // 业务数据处理
        System.out.println(Jsons.DEFAULT.toJson(resp.getData()));
    }
}
